"""
Класс для описания стилей терминала.
Класс для журналирования в терминал.
Класс с украшательствами для консоли.

Author: Milinuri Nirvalen
"""

import datetime
import os
import shutil


################################################################################
# Colors <-- цвета для терминале
################################################################################

class Colors:
	def __init__(self):
		super(Colors, self).__init__()
		# словарь цыетоы
		self.colors = {'black':'\033[30m', 'red':'\033[31m',
					   'green':'\033[32m', 'yellow':'\033[33m',
					   'blue':'\033[34m','magenta':'\033[35m',
					   'cyan':'\033[36m', 'white':'\033[37m',

					   'gray':'\033[90m', 'lred':'\033[91m',
					   'lgreen':'\033[92m', 'lyellow':'\033[93m',
					   'lblue':'\033[94m', 'lmagenta':'\033[95m',
				  	   'lcyan':'\033[96m', 'lwhite':'\033[97m',
				  	   'reset':'\033[0m'}

		# добавляем словарь цветов в атрибуты класса
		self.__dict__.update(self.colors)

	def colortest(self):
		# выводит все цвета класса Colors
		for k, v in self.colors.items():
			print(v + k, end=' ')
		print(self.reset+'|')

	def rc(self, text):
		"""очищает текст от цыетовых кодов, полезно для len()
		:param text: входной текст
		:returns: текст без названия цветов"""
		for k in self.colors.values():
			text = text.replace(k, '')

		return text


################################################################################
# Logger <-- логгирование в терминале
################################################################################

class Logger(Colors):
	"""Логгирование в терминале, запись логов в файл"""
	def __init__(self, name='main', print_name=True):
		super(Logger, self).__init__()
		self.print_name = print_name
		if print_name:
			self.name = name
		else:
			self.name = ''


	def set_group(self, text):
		'''заменяет специальные метки, на значки логов
		:param text: текст, в котором нужно преобразовать группы

		:return: преобразованный текст'''

		groups = {'<i>':f'{self.lyellow}[=]{self.reset}',
    		'<c>':f'{self.lyellow}[+]{self.reset}',
    		'<w>':f'{self.lyellow}[!]{self.reset}',
    		'<e>':f'{self.lyellow}[-]{self.reset}'}

		for par, arg in groups.items():
			text = text.replace(par, arg)
		return text


	def date(self):
		t = datetime.datetime.now().strftime('%H:%M:%S.%f|')
		return self.gray+t+self.reset


	def log(self, text, log_type='i'):
		"""выводит сообщение в терминал
		:param text: тест сообщения
		:optional param log_type: тип сообщения
			i (info) - информационное
			c (continue) - завершено
			w (warn) - предупрждение
			e (error) - ошибка
			также можно указать тип логов и добавить <i/c/w/e>"""

		groups = {'i':f'{self.cyan}[=] {self.gray}{self.name}{self.reset}',
				'c':f'{self.green}[+] {self.gray}{self.name}{self.lgreen}',
				'w':f'{self.lyellow}[!] {self.yellow}{self.name}{self.lyellow}',
				'e':f'{self.lyellow}[-] {self.yellow}{self.name}{self.lred}'}

		if log_type in groups:
			group = groups[log_type]
		elif log_type:
			group = f'{self.lcyan}{self.name} {self.gray}{log_type}{self.reset}'
		else:
			group = f'{self.gray}{self.name}{self.reset}'

		log_text = f'{self.date()} {self.set_group(group)} {text} {self.reset}'
		print(f'{log_text}{" "*(shutil.get_terminal_size()[0]-len(log_text))}')

	def logtest(self):
		# выводит все типы логов
		types = [None, 'i', 'c', 'w', 'e',
				'abc', 'abc <i>', 'abd <c>', 'abc <w>', 'abc <e>']
		for x in types:
			self.log('text', x)

	"""
	некоторые украшательства
	"""

	def info(self, text):
		self.log(text, 'i')

	def complite(self, text):
		self.log(text, 'c')

	def warn(self, text):
		self.log(text, 'w')

	def error(self, text):
		self.log(text, 'e')


################################################################################
# Ui <-- украшательства в терминале
################################################################################

class Ui(Colors):
	"""docstring for Ui"""
	def __init__(self, name=None):
		super(Ui, self).__init__()
		self.l = Logger(name)
		self.name = name

		# настройки внешнего вида
		self.mc = '<gray>'
		self.bc = '<mage>'
		self.tc = '<lcya>'

		# получаем размер терминала
		self.get_size()


	def colored(self, text):
		# преобразует ключевые слова в цветовые коды
		codes = {'<m>':self.mc, '<b>':self.bc, '<t>':self.tc, '<r>':self.reset}
		for k, v in codes.items():
			text = text.replace(k, v)

		for k, v in self.colors.items():
			text = text.replace(f'<{k[0:4]}>', v)

		text += self.reset
		return text


	def cprint(self, text, **params):
		print(self.colored(text), **params)


	def clear(self):
		# очищает терминал
		if os.name == 'nt':
			os.system('cls')
		else:
			os.system('clear')


	def get_size(self):
		# получение размера окна терминала и обновление этих данных
		s = shutil.get_terminal_size()
		self.size = [s[0], s[1]]


	def row(self, name=None):
		'''отрисовывает визуальный разделитель
		: param name :  имя для разделителя'''
		if not name:
			self.cprint(f"<m>{'─'*self.size[0]}")
		else:
			sep = round((self.size[0]-len(name)-7))
			self.cprint(f'<m>{"─"*5} <t>{name} <m>{"─"*sep}')


	def param(self, k, v=''):
		self.cprint(f'<b>{k[0].upper()}{k[1:]}<r>: <t>{v}')


	def dict_to_list(self, target):
		# преобразует словарь в список
		temp = []
		for k, v in target.items():
			temp.append(self.colored(f'<t>{k}<r>: {v}'))
		return temp


	def print_list(self, target, name=''):
		if type(target) == dict:
			target = self.dict_to_list(target)

		self.param(f"[{len(target)}] " + name or 'items')

		for u in range(len(target)):
			name = target[u]
			if u == (len(target)-1):
				print(self.colored(f'  <m>└───<b>[<t>{name}'))
			else:
				print(self.colored(f'  <m>├───<b>[<t>{name}'))


	def decor_arg(self, arg, decor= {'0': 'нет', '1': 'да'}):
		for k, v in decor.items():
			arg = str(arg).replace(str(k), str(v))
		return arg


	def form(self, text):

		if isinstance(text, list):
			pass
		elif isinstance(text, str):
			text = text.split('\n')
		elif isinstance(text, dict):
			text = self.dict_to_list(text)
		else:
			text = str(text)

		s = self.size[0]-10
		st = s-4

		print('\n'+' '*5+'┏'+'━'*(s-3)+'┑'+' '*5)

		for line in text:
			if len(self.rc(line)) < st:
				self.cprint(f'     ┃ {line}{" "*(st-len(self.rc(line)))}│     ')

			else:
				i = round(len(self.rc(line))/st)
				for x in range(round(len(self.rc(line))/st)):
					if x != i:
						string = line[x*st:(x+1)*st]
					else:
						string = line[x*st:]

					self.cprint(f'     ┃ {string}{" "*(st-len(string))}│     ')


		print(' '*5+'┖'+'─'*(s-3)+'┘'+' '*5)

	def progress_bar(self, iteration, total,
					  suffix = '',
					  prefix = '',
					  length = None,
					  sim_on = '▰',
					  printEnd = "\n",
					  hide=False,
					  colors=False):

		if not length:
			length = round(self.size[0] / 100 * 40)

		if type(iteration) == int:
			iterations = [(iteration,'')]
		elif type(iteration) == list:
			iterations = iteration

		percent = round(100 * sum(map(lambda x: x[0], iterations)) / total, 1)

		if colors:
			if percent > 75:
				color = self.lcyan
			elif percent > 50:
				color = self.lgreen
			elif percent > 25:
				color = self.lyellow
			else:
				color = self.lred
		else:
			color = self.reset

		bar = color
		for x in iterations:
			k, v = x
			bar += v + sim_on*int(length * k / total)

		bar += self.reset + ' ' * (length - int(length * sum(map(lambda x: x[0], iterations)) / total))

		text = f'\r{prefix} |{bar}| {sum(map(lambda x: x[0], iterations))}/{total} ({percent}) {suffix}'
		if not hide:
			self.cprint(text, end= printEnd)
		return text


	def window(self, *lines, **params):
		# border
		border_type = params.get('border', 'standart')
		scheme = params.get('scheme', ['h', 'm', 'f'])
		indent = 0
		borders = {'standart':['╔', '╗', '╚', '╝', '═', '║'],
				   'retro': ['+', '+', '+', '+', '-', '|']}
		border = borders[border_type]

		# lenght window
		if 'lenght' in params:
			line = params['lenght']
		else:
			line = max([ len(x) for x in lines])
			if line % 2:
				line += 1

		if params.get('pos') == 'right':
			indent = self.size[0] - 2 - line

		# render
		for x in scheme:
			if x == 'h':
				print(' '*indent+border[0]+border[4]*line+border[1])
			elif x == 'f':
				print(' '*indent+border[2]+border[4]*line+border[3])
			elif x == 'm':
				for l in lines:
					print(' '*indent+border[5]+l+' '*(line-len(l))+border[5])
